package com.coder4j.starter.tools;

import com.alibaba.fastjson.JSON;
import com.coder4j.starter.tools.util.DateUtils;
import com.coder4j.starter.tools.vo.MonitorVO;
import com.sun.management.OperatingSystemMXBean;


import java.io.File;
import java.lang.management.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 监控工具类，用于监控系统及JVM运行状态
 * @author keller
 * @date 2024-5-27 09:35:58
 */
public class MonitorUtils {

    public static void main(String[] args) {
        getMonitorVO();
    }

    public static final int MB  = 1012*1024;

    public static final int GB = MB * 1024;

    public static MonitorVO getMonitorVO(){
        MonitorVO vo = new MonitorVO();

        MonitorVO.OS os = new MonitorVO.OS();
        OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        os.setName(osBean.getName());
        os.setVersion(osBean.getVersion());
        os.setArch(osBean.getArch());
        vo.setOs(os);

        MonitorVO.CPU cpu = new MonitorVO.CPU();
        cpu.setCpuProcessors(osBean.getAvailableProcessors());
        cpu.setProcessCpuLoad(new Double(osBean.getProcessCpuLoad() * 100).intValue());
        cpu.setSystemCpuLoad(new Double(osBean.getSystemCpuLoad() * 100).intValue());
        vo.setCpu(cpu);

        vo.setMemory(getMemory(osBean));
        vo.setDisks(getDisks());
        vo.setJvm(getJvmInfo());
        //线程
        vo.setJvmThread(getJVMThread());
        //Jvm内存
        vo.setJvmMemory(getJvmMemory());
        vo.setJvmClassLoad(getJvmClassLoad());
        vo.setJvmMemoryPools(getJVMMemoryPoolList());
        vo.setJvmgcList(getJVMGCList());


        System.out.println(JSON.toJSONString(vo));
        return vo;
    }

    private static List<MonitorVO.JVMGC> getJVMGCList() {
        List<MonitorVO.JVMGC> list = new ArrayList<>();

        // 获取所有GarbageCollectorMXBean实例
        List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();

        // 遍历所有垃圾收集器并打印相关信息
        for (GarbageCollectorMXBean gcBean : gcBeans) {
            MonitorVO.JVMGC vo = new MonitorVO.JVMGC();
            vo.setName(gcBean.getName());
            vo.setCollectionCount(gcBean.getCollectionCount());
            vo.setCollectionTime(gcBean.getCollectionTime());
            String[] names = gcBean.getMemoryPoolNames();
            if(names != null){
                vo.setMemoryPoolNames(Arrays.asList(names));
            }
            list.add(vo);
        }
        return list;
    }

    private static List<MonitorVO.JVMMemoryPool> getJVMMemoryPoolList() {
        List<MonitorVO.JVMMemoryPool> list = new ArrayList<>();
        //内存池
        List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();

        for (MemoryPoolMXBean pool : pools) {
            MonitorVO.JVMMemoryPool vo = new MonitorVO.JVMMemoryPool();
            vo.setName(pool.getName());
            vo.setType(pool.getType().name());

            MemoryUsage usage = pool.getUsage();
            if (usage != null) {
                vo.setInitSpace(new Long(usage.getInit()/MB).intValue());
                vo.setUsedSpace(new Long(usage.getUsed()/MB).intValue());
                vo.setMaxSpace(new Long(usage.getMax()/MB).intValue());
            }
            usage = pool.getCollectionUsage();
            if(usage!=null){
                vo.setCollectionUsedSpace(new Long(usage.getUsed()/MB).intValue());
                vo.setCollectionMaxSpace(new Long(usage.getMax()/MB).intValue());
            }
            String[] managerNames = pool.getMemoryManagerNames();
            if(managerNames != null){
                vo.setManagers(Arrays.asList(managerNames));
            }
            list.add(vo);
        }
        return list;
    }

    private static MonitorVO.JVMClassLoad getJvmClassLoad() {
        MonitorVO.JVMClassLoad vo = new MonitorVO.JVMClassLoad();
        ClassLoadingMXBean classLoading = ManagementFactory.getClassLoadingMXBean();
        vo.setLoadedClassCount(classLoading.getLoadedClassCount());
        vo.setUnloadedClassCount(classLoading.getUnloadedClassCount());
        vo.setTotalLoadedThreadCount(classLoading.getTotalLoadedClassCount());
        return vo;
    }

    private static MonitorVO.JVM getJvmInfo() {
        MonitorVO.JVM jvm = new MonitorVO.JVM();
        //运行时
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        jvm.setName(runtimeMXBean.getVmName());
        jvm.setVersion(runtimeMXBean.getVmVersion());
        jvm.setInputArguments(runtimeMXBean.getInputArguments());
        jvm.setClassPath(runtimeMXBean.getClassPath());
        jvm.setStartTime(new Date(runtimeMXBean.getStartTime()));
        jvm.setRunTime(new Long(runtimeMXBean.getUptime() / 1000).intValue());
        jvm.setRunTimeStr(DateUtils.getDurationString(jvm.getStartTime()));
        return jvm;
    }

    private static List<MonitorVO.Disk> getDisks() {
        List<MonitorVO.Disk> disks = new ArrayList<>();
        File[] roots = File.listRoots();
        if(roots != null){
            for (File root : roots) {
                MonitorVO.Disk disk = new MonitorVO.Disk();
                disk.setName(root.getAbsolutePath());
                disk.setTotalSpace(new Long(root.getTotalSpace()/GB).intValue());
                disk.setFreeSpace(new Long(root.getFreeSpace()/GB).intValue());
                disk.setUsedSpace(disk.getTotalSpace() - disk.getFreeSpace());
                disk.setLoad(new Double(new Double(disk.getUsedSpace())/disk.getTotalSpace() * 100).intValue());
                disks.add(disk);
            }
        }
        return disks;
    }

    private static MonitorVO.JVMThread getJVMThread() {
        ThreadMXBean mxThread = ManagementFactory.getThreadMXBean();
        MonitorVO.JVMThread thread = new MonitorVO.JVMThread();
        thread.setThreadCount(mxThread.getThreadCount());
        thread.setDaemonThreadCount(mxThread.getDaemonThreadCount());
        thread.setPeakThreadCount(mxThread.getPeakThreadCount());
        thread.setTotalStartedThreadCount(mxThread.getTotalStartedThreadCount());
        return thread;
    }

    private static MonitorVO.JVMMemory getJvmMemory() {
        MonitorVO.JVMMemory jvmMemory = new MonitorVO.JVMMemory();
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heapMemory = memoryMXBean.getHeapMemoryUsage();
        jvmMemory.setMaxHeapMemory(new Long(heapMemory.getMax()/MB).intValue());
        jvmMemory.setUsedHeapMemory(new Long(heapMemory.getUsed()/MB).intValue());
        jvmMemory.setFreeHeapMemory(jvmMemory.getMaxHeapMemory() - jvmMemory.getUsedHeapMemory());
        jvmMemory.setHeapMemoryLoad(new Double(new  Double(jvmMemory.getUsedHeapMemory() + "")/jvmMemory.getMaxHeapMemory() * 100).intValue());
        MemoryUsage nonHeapMemory = memoryMXBean.getNonHeapMemoryUsage();
        jvmMemory.setUsedNonHeapMemory(new Long(nonHeapMemory.getUsed()/MB).intValue());
        return jvmMemory;
    }

    private static MonitorVO.Memory getMemory(OperatingSystemMXBean osBean) {
        MonitorVO.Memory memory = new MonitorVO.Memory();
        memory.setTotalMemory(new Long(osBean.getTotalPhysicalMemorySize()/GB).intValue());
        memory.setFreeMemory(new Long(osBean.getFreePhysicalMemorySize()/GB).intValue());
        memory.setUsedMemory(memory.getTotalMemory() - memory.getFreeMemory());
        memory.setMemoryLoad(new Double(new Double(memory.getUsedMemory() + "")/memory.getTotalMemory() * 100).intValue());
        memory.setTotalVirtualMemory(new Long(osBean.getTotalSwapSpaceSize()/GB).intValue());
        memory.setFreeVirtualMemory(new Long(osBean.getFreeSwapSpaceSize()/GB).intValue());
        memory.setUsedVirtualMemory(memory.getTotalVirtualMemory() - memory.getFreeVirtualMemory());
        memory.setVirtualMemoryLoad(new Double(new Double(memory.getUsedVirtualMemory() + "")/memory.getTotalVirtualMemory() * 100).intValue());
        return memory;
    }

}
